package com.tutos.ui.monitor;

import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.inject.Inject;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

import com.tutos.GuiceServletInjector;
import com.tutos.ui.monitor.Eventos;
import com.tutos.dao.MonitorDAO;
import com.tutos.model.Evento;
import com.tutos.model.Monitor;
import com.tutos.ui.TutosApplication;

import com.vaadin.addon.calendar.event.BasicEventProvider;
import com.vaadin.addon.calendar.event.CalendarEvent;
import com.vaadin.addon.calendar.ui.Calendar;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickEvent;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventClick;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventClickHandler;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResize;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.MoveEvent;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectEvent;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectHandler;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClick;
import com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler;
import com.vaadin.addon.calendar.ui.handler.BasicDateClickHandler;
import com.vaadin.addon.calendar.ui.handler.BasicEventMoveHandler;
import com.vaadin.addon.calendar.ui.handler.BasicEventResizeHandler;
import com.vaadin.addon.calendar.ui.handler.BasicWeekClickHandler;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.util.BeanItem;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Field;
import com.vaadin.ui.Form;
import com.vaadin.ui.FormFieldFactory;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.Select;
import com.vaadin.ui.Slider;
import com.vaadin.ui.Slider.ValueOutOfBoundsException;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.TabSheet.Tab;
import com.vaadin.ui.Window.CloseEvent;
import com.vaadin.ui.Window.CloseListener;
import com.vaadin.ui.Window.Notification;

/** Calendar component test application */
public class HorarioGrafico {

	private VerticalLayout layout = new VerticalLayout();
	private Monitor monitor;
	private MonitorDAO monitorDAO;
	private enum Mode {	MONTH, WEEK, DAY;}

	/**
	 * This Gregorian calendar is used to control dates and time inside of this
	 * test application.
	 */
	private GregorianCalendar calendar;

	/** Target calendar component that this test application is made for. */
	private Calendar calendarComponent;
	private Date currentMonthsFirstDate;
	private Label captionLabel = new Label("");
	private Button monthButton, weekButton, nextButton, prevButton;
	private Button deleteEventButton, applyEventButton, repeatEventButton;
	private Window scheduleEventPopup;
	private final Form scheduleEventForm = new Form();
	private NativeSelect repeatTipe;
	private Accordion accordion;
	private Tab inferior, superior;
	private Slider slider;
	private Mode viewMode = Mode.MONTH;
	private MyBasicEventProvider dataSource;
	private Button addNewEvent;
	private boolean readOnly;

	@Inject
	public HorarioGrafico(MonitorDAO monitorDAO) {
    	this.monitorDAO=monitorDAO;
		layout.setSizeFull();
		layout.setMargin(true);
		initContent();
	}

	public void initContent() {
		initCalendar();
		initLayoutContent();
	}

	public void init(){
		Subject currentUser = SecurityUtils.getSubject();
		currentUser.getSession().getAttribute("username");
		setReadOnly(false);
		addNewEvent.setEnabled(true);
		setMonitor(monitorDAO.getMonitorByCorreo((String) currentUser.getSession().getAttribute("username")));
	}
	
	public void init(Monitor monitor){
		setReadOnly(true);
		addNewEvent.setEnabled(false);
		setMonitor(monitor);
	}
	
	private void setMonitor(Monitor newMonitor){
		monitor = newMonitor;
		
		if(monitor.getHorario() == null){
			ArrayList<Evento> horario = new ArrayList<Evento>();
			monitor.setHorario(horario);
		}
		
		dataSource = new MyBasicEventProvider(monitor.getHorario());
		calendarComponent.setEventProvider(dataSource);
	}
	
	private void initLayoutContent() {
		initNavigationButtons();
		initAddNewEventButton();

		HorizontalLayout hl = new HorizontalLayout();
		hl.setWidth("100%");
		hl.setSpacing(true);
		hl.setMargin(false, false, true, false);
		hl.addComponent(prevButton);
		hl.addComponent(captionLabel);
		hl.addComponent(monthButton);
		hl.addComponent(weekButton);
		hl.addComponent(nextButton);
		hl.setComponentAlignment(prevButton, Alignment.MIDDLE_LEFT);
		hl.setComponentAlignment(captionLabel, Alignment.MIDDLE_CENTER);
		hl.setComponentAlignment(monthButton, Alignment.MIDDLE_CENTER);
		hl.setComponentAlignment(weekButton, Alignment.MIDDLE_CENTER);
		hl.setComponentAlignment(nextButton, Alignment.MIDDLE_RIGHT);

		monthButton.setVisible(viewMode == Mode.WEEK);
		weekButton.setVisible(viewMode == Mode.DAY);

		HorizontalLayout controlPanel = new HorizontalLayout();
		controlPanel.setSpacing(true);
		controlPanel.setMargin(false, false, true, false);
		controlPanel.setWidth("100%");
		
		controlPanel.addComponent(addNewEvent);
		controlPanel.setComponentAlignment(addNewEvent, Alignment.MIDDLE_CENTER);

		layout.addComponent(controlPanel);
		layout.addComponent(hl);
		layout.addComponent(calendarComponent);
		layout.setExpandRatio(calendarComponent, 1);
	}

	private void initNavigationButtons() {
		monthButton = new Button("Vista mensual", new ClickListener() {

			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				switchToMonthView();
			}
		});

		weekButton = new Button("Vista semanal", new ClickListener() {

			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				// simulate week click
				WeekClickHandler handler = (WeekClickHandler) calendarComponent
						.getHandler(WeekClick.EVENT_ID);
				handler.weekClick(new WeekClick(calendarComponent, calendar
						.get(GregorianCalendar.WEEK_OF_YEAR), calendar
						.get(GregorianCalendar.YEAR)));
			}
		});

		nextButton = new Button("Siguiente", new Button.ClickListener() {
			
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				handleNextButtonClick();
			}
		});

		prevButton = new Button("Anterior", new Button.ClickListener() {
			
			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				handlePreviousButtonClick();
			}
		});
	}

	public void initAddNewEventButton() {
		addNewEvent = new Button();
		addNewEvent.setIcon(new ThemeResource("fecha.gif"));
		addNewEvent.setDescription("Agregar");
		
		addNewEvent.addListener(new Button.ClickListener() {

			private static final long serialVersionUID = -8307244759142541067L;

			public void buttonClick(ClickEvent event) {
				showEventPopup(createNewEvent(new Date(), new Date()), true);
			}

		});
	}

	private void initCalendar() {
		
		calendarComponent = new Calendar();
		calendarComponent.setLocale(TutosApplication.getInstance().getMainWindow().getLocale());
		calendarComponent.setImmediate(true);
		calendarComponent.setSizeFull();

		calendar = new GregorianCalendar(TutosApplication.getInstance().getMainWindow().getLocale());
		calendar.setTime(new Date());

		updateCaptionLabel();

		int rollAmount = calendar.get(GregorianCalendar.DAY_OF_MONTH) - 1;
		calendar.add(GregorianCalendar.DAY_OF_MONTH, -rollAmount);
		resetTime(false);
		currentMonthsFirstDate = calendar.getTime();
		calendarComponent.setStartDate(currentMonthsFirstDate);
		calendar.add(GregorianCalendar.MONTH, 1);
		calendar.add(GregorianCalendar.DATE, -1);
		calendarComponent.setEndDate(calendar.getTime());

		addCalendarEventListeners();
	}

	@SuppressWarnings("serial")
	private void addCalendarEventListeners() {
		// Register week clicks by changing the schedules start and end dates.
		calendarComponent.setHandler(new BasicWeekClickHandler() {

			@Override
			public void weekClick(WeekClick event) {
				// let BasicWeekClickHandler handle calendar dates, and update
				// only the other parts of UI here
				super.weekClick(event);
				updateCaptionLabel();
				switchToWeekView();
			}
		});

		calendarComponent.setHandler(new EventClickHandler() {

			public void eventClick(EventClick event) {
				showEventPopup(event.getCalendarEvent(), false);
			}
		});

		calendarComponent.setHandler(new BasicDateClickHandler() {

			@Override
			public void dateClick(DateClickEvent event) {
				// let BasicDateClickHandler handle calendar dates, and update
				// only the other parts of UI here
				super.dateClick(event);
				switchToDayView();
			}
		});

		calendarComponent.setHandler(new RangeSelectHandler() {

			public void rangeSelect(RangeSelectEvent event) {
				if(!readOnly)
					handleRangeSelect(event);
			}
		});
		
		calendarComponent.setHandler(new BasicEventMoveHandler() {

			@Override
			public void eventMove(MoveEvent event) {
				if(!readOnly){
					super.eventMove(event);
					CalendarEvent calendarEvent = event.getCalendarEvent();
					((Eventos) calendarEvent).setStyleName("color4");
					monitorDAO.updateEntity(monitor);
				}
				calendarComponent.setImmediate(true);
			}

		});
		
		calendarComponent.setHandler(new BasicEventResizeHandler() {
			
			@Override
			public void eventResize(EventResize event){
				if(!readOnly){
					super.eventResize(event);
					CalendarEvent calendarEvent = event.getCalendarEvent();
					((Eventos) calendarEvent).setStyleName("color4");
					monitorDAO.updateEntity(monitor);
				}
				calendarComponent.setImmediate(true);
			}
		});
	}

	private void handleNextButtonClick() {
		switch (viewMode) {
		case MONTH:
			nextMonth();
			break;
		case WEEK:
			nextWeek();
			break;
		case DAY:
			nextDay();
			break;
		}
	}

	private void handlePreviousButtonClick() {
		switch (viewMode) {
		case MONTH:
			previousMonth();
			break;
		case WEEK:
			previousWeek();
			break;
		case DAY:
			previousDay();
			break;
		}
	}

	private void handleRangeSelect(RangeSelectEvent event) {
		Date start = event.getStart();
		Date end = event.getEnd();

		/*
		 * If a range of dates is selected in monthly mode, we want it to end at
		 * the end of the last day.
		 */
		if (event.isMonthlyMode()) {
			end = Calendar.getEndOfDay(calendar, end);
		}

		showEventPopup(createNewEvent(start, end), true);
	}

	private void showEventPopup(CalendarEvent event, boolean newEvent) {
		if (event == null) {
			return;
		}

		updateCalendarEventPopup(newEvent);
		updateCalendarEventForm(event);

		scheduleEventForm.setReadOnly(readOnly);
		
		if (!TutosApplication.getInstance().getMainWindow().getChildWindows().contains(scheduleEventPopup)) {
			TutosApplication.getInstance().getMainWindow().addWindow(scheduleEventPopup);
		}
	}

	/* Initializes a modal window to edit schedule event. */
	@SuppressWarnings("deprecation")
	private void createCalendarEventPopup() {
		VerticalLayout layout = new VerticalLayout();
		layout.setMargin(true);
		layout.setSpacing(true);
		layout.setSizeFull();
		
		accordion = new Accordion();
		accordion.setHeight("250px");
		accordion.setWidth("398px");
		
		VerticalLayout layoutExtend = new VerticalLayout();
		layoutExtend.setMargin(true);
		layoutExtend.setSpacing(true);
		
		final Label repeticiones = new Label("0");
		repeticiones.setWidth("3em");
		
		slider = new Slider("Escoja el numero de repeticiones:", 1, 100);
        slider.setWidth("100%");
        slider.setImmediate(true);

        final String[] valuesRepeat = {"Diaria", "Semanal", "Mensual"};
        repeatTipe = new NativeSelect("Tipo repetición");
        repeatTipe.addItem(valuesRepeat[0]);
        repeatTipe.addItem(valuesRepeat[1]);
        repeatTipe.addItem(valuesRepeat[2]);
        repeatTipe.setNullSelectionAllowed(false);
        repeatTipe.setValue(valuesRepeat[0]);
        repeatTipe.setImmediate(true);
		
		scheduleEventPopup = new Window(null, accordion);
		scheduleEventPopup.setWidth("400px");
		scheduleEventPopup.setModal(true);
		scheduleEventPopup.setResizable(false);
		scheduleEventPopup.center();

		layout.addComponent(scheduleEventForm);

		applyEventButton = new Button("Aplicar", new ClickListener() {

			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				commitCalendarEvent();
			}
		});
		Button cancel = new Button("Cancelar", new ClickListener() {

			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				discardCalendarEvent();
			}
		});
		deleteEventButton = new Button("Borrar", new ClickListener() {

			private static final long serialVersionUID = 1L;

			public void buttonClick(ClickEvent event) {
				deleteCalendarEvent();
			}
		});
		scheduleEventPopup.addListener(new CloseListener() {

			private static final long serialVersionUID = 1L;

			public void windowClose(CloseEvent e) {
				discardCalendarEvent();
			}
		});

		repeatEventButton = new Button("Repetir", new ClickListener() {
			
			private static final long serialVersionUID = 1L;
			
			public void buttonClick(ClickEvent event) {
				double value = (Double) slider.getValue();
				repeatCalendarEvent(value, repeatTipe.getValue());
				TutosApplication.getInstance().getMainWindow().showNotification(new Notification("Repeticiones añadidas",
					    "<br/>Añadidas " + (int)value 
						+ " repeticiones de manera " + repeatTipe.getValue(),
					    Notification.TYPE_WARNING_MESSAGE, true));
				
				try {
					slider.setValue(1);
				} catch (ValueOutOfBoundsException e) {
					e.printStackTrace();
				}
			}
		});
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		buttons.addComponent(deleteEventButton);
		buttons.addComponent(applyEventButton);
		buttons.addComponent(cancel);
		layout.addComponent(buttons);
		layout.setComponentAlignment(buttons, Alignment.BOTTOM_RIGHT);
		
		HorizontalLayout horizontalLayout = new HorizontalLayout();
		horizontalLayout.setSpacing(true);
		
		horizontalLayout.addComponent(repeatTipe);
		horizontalLayout.addComponent(repeatEventButton);
		horizontalLayout.setComponentAlignment(repeatTipe, Alignment.MIDDLE_CENTER);
		horizontalLayout.setComponentAlignment(repeatEventButton, Alignment.MIDDLE_CENTER);
		
		layoutExtend.addComponent(slider);
		layoutExtend.addComponent(horizontalLayout);
		layoutExtend.setComponentAlignment(horizontalLayout, VerticalLayout.ALIGNMENT_HORIZONTAL_CENTER, VerticalLayout.ALIGNMENT_VERTICAL_CENTER);
				
		superior = accordion.addTab(layout, "Editar");
		inferior = accordion.addTab(layoutExtend, "Repetir fecha");
	}

	private void updateCalendarEventPopup(boolean newEvent) {
		if (scheduleEventPopup == null) {
			createCalendarEventPopup();
		}

		deleteEventButton.setVisible(!newEvent);
		deleteEventButton.setEnabled(!readOnly);
		applyEventButton.setEnabled(!readOnly);
		inferior.setVisible(!readOnly);
		
		if (newEvent) {
			scheduleEventPopup.setCaption("Nuevo evento");
			superior.setCaption("Datos");
			inferior.setVisible(false);
			
		} else {
			
			if(readOnly){
				scheduleEventPopup.setCaption("Evento");
				superior.setCaption("Datos");
			}else{
				scheduleEventPopup.setCaption("Editar evento");
				superior.setCaption("Editar");
			}
			accordion.setSelectedTab(superior);
			inferior.setVisible(!readOnly);
		}
	}

	private void updateCalendarEventForm(CalendarEvent event) {
		// Lets create a CalendarEvent BeanItem and pass it to the form's data
		// source.
		BeanItem<CalendarEvent> item = new BeanItem<CalendarEvent>(event);
		scheduleEventForm.setWriteThrough(false);
		scheduleEventForm.setItemDataSource(item);
		scheduleEventForm.setFormFieldFactory(new FormFieldFactory() {

			private static final long serialVersionUID = 1L;

			public Field createField(Item item, Object propertyId,
					Component uiContext) {
				if (propertyId.equals("caption")) {
					TextField f = createTextField("Nombre");
					f.focus();
					return f;

				} else if (propertyId.equals("where")) {
					return createTextField("Lugar");

				} else if (propertyId.equals("description")) {
					TextField f = createTextField("Descripción");
					return f;

				} else if (propertyId.equals("styleName")) {
					return createStyleNameSelect();

				} else if (propertyId.equals("start")) {
					return createDateField("Fecha inicio");

				} else if (propertyId.equals("end")) {
					return createDateField("Fecha fin");
				} else if (propertyId.equals("allDay")) {
					CheckBox cb = createCheckBox("Todo el día");

					cb.addListener(new Property.ValueChangeListener() {

						private static final long serialVersionUID = -7104996493482558021L;

						public void valueChange(ValueChangeEvent event) {
							Object value = event.getProperty().getValue();
							if (value instanceof Boolean
									&& Boolean.TRUE.equals(value)) {
								setFormDateResolution(DateField.RESOLUTION_DAY);

							} else {
								setFormDateResolution(DateField.RESOLUTION_MIN);
							}
						}

					});

					return cb;
				}
				return null;
			}

			private CheckBox createCheckBox(String caption) {
				CheckBox cb = new CheckBox(caption);
				cb.setImmediate(true);
				return cb;
			}

			private TextField createTextField(String caption) {
				TextField f = new TextField(caption);
				f.setNullRepresentation("");
				return f;
			}

			private DateField createDateField(String caption) {
				DateField f = new DateField(caption);
				f.setResolution(DateField.RESOLUTION_MIN);
				return f;
			}

			private Select createStyleNameSelect() {
				Select s = new Select("Color");
				s.addContainerProperty("c", String.class, "");
				s.setItemCaptionPropertyId("c");
				Item i = s.addItem("color1");
				i.getItemProperty("c").setValue("Verde");
				i = s.addItem("color2");
				i.getItemProperty("c").setValue("Azul");
				i = s.addItem("color3");
				i.getItemProperty("c").setValue("Rojo");
				i = s.addItem("color4");
				i.getItemProperty("c").setValue("Naranja");
				return s;
			}
		});

		scheduleEventForm
				.setVisibleItemProperties(new Object[] { "start", "end",
						"allDay" });
	}

	private void setFormDateResolution(int resolution) {
		if (scheduleEventForm.getField("start") != null
				&& scheduleEventForm.getField("end") != null) {
			((DateField) scheduleEventForm.getField("start"))
					.setResolution(resolution);
			((DateField) scheduleEventForm.getField("start")).requestRepaint();
			((DateField) scheduleEventForm.getField("end"))
					.setResolution(resolution);
			((DateField) scheduleEventForm.getField("end")).requestRepaint();
		}
	}
	
	public boolean isReadOnly() {
		return readOnly;
	}

	public void setReadOnly(boolean readOnly) {
		this.readOnly = readOnly;
	}

	private CalendarEvent createNewEvent(Date startDate, Date endDate) {

		Eventos event = new Eventos();
		event.setCaption("");
		event.setStart(startDate);
		event.setEnd(endDate);
		event.setStyleName("color1");
		return event;
	}

	/* Removes the event from the data source and fires change event. */
	private void deleteCalendarEvent() {
		Eventos event = getFormCalendarEvent();
		if (dataSource.containsEvent(event)) {
			dataSource.removeEvent(event);
			monitorDAO.updateEntity(monitor);
		}
		TutosApplication.getInstance().getMainWindow().removeWindow(scheduleEventPopup);
	}

	/* Adds/updates the event in the data source and fires change event. */
	private void commitCalendarEvent() {
		scheduleEventForm.commit();
		Eventos event = getFormCalendarEvent();
		event.setStyleName("color1");
		if (!dataSource.containsEvent(event)) {
			dataSource.addEvent(event);
			monitorDAO.updateEntity(monitor);
		}

		TutosApplication.getInstance().getMainWindow().removeWindow(scheduleEventPopup);
	}

	private void discardCalendarEvent() {
		scheduleEventForm.discard();
		monitorDAO.updateEntity(monitor);
		TutosApplication.getInstance().getMainWindow().removeWindow(scheduleEventPopup);
	}
	
	/*Creates and adds the number of repetitions especified by the parameters */
	private void repeatCalendarEvent(double repetitions, Object tipe){
		scheduleEventForm.commit();
		Eventos event = getFormCalendarEvent();

		GregorianCalendar repetitionTimeStart = new GregorianCalendar();
		GregorianCalendar repetitionTimeEnd = new GregorianCalendar();
		
		int tipoSuma, valor;
		
		if(tipe.equals("Diaria")){//Repetición del evento diariamente
			tipoSuma = GregorianCalendar.DAY_OF_WEEK;
			valor = 1;
		}else if(tipe.equals("Semanal")){//Repetición del evento semanalmente
			tipoSuma = GregorianCalendar.DAY_OF_WEEK;
			valor = 7;
		}else{//Repetición del evento mensualmente
			tipoSuma = GregorianCalendar.DAY_OF_WEEK;
			valor = 28;
		}
		
		Eventos ev;
		
		//For que crea y añade las repeticiones sumando el tiempo a repetir
		for(int i = 0; i < (int)repetitions; i++){
			repetitionTimeStart.setTime(event.getStart());
			repetitionTimeEnd.setTime(event.getEnd());
			
			repetitionTimeStart.add(tipoSuma, valor);
			repetitionTimeEnd.add(tipoSuma, valor);
			
			 ev = new Eventos(repetitionTimeStart.getTime(), repetitionTimeEnd.getTime(), event.isAllDay());
			 ev.setStyleName("color2");
			 dataSource.addEvent(ev);
			 event = ev;
		}
		monitorDAO.updateEntity(monitor);
		calendarComponent.setImmediate(true);
		TutosApplication.getInstance().getMainWindow().removeWindow(scheduleEventPopup);
	}

	@SuppressWarnings("unchecked")
	private Eventos getFormCalendarEvent() {
		BeanItem<CalendarEvent> item = (BeanItem<CalendarEvent>) scheduleEventForm
				.getItemDataSource();
		CalendarEvent event = item.getBean();
		return (Eventos) event;
	}

	private void nextMonth() {
		rollMonth(1);
	}

	private void previousMonth() {
		rollMonth(-1);
	}

	private void nextWeek() {
		rollWeek(1);
	}

	private void previousWeek() {
		rollWeek(-1);
	}

	private void nextDay() {
		rollDate(1);
	}

	private void previousDay() {
		rollDate(-1);
	}

	private void rollMonth(int direction) {
		calendar.setTime(currentMonthsFirstDate);
		calendar.add(GregorianCalendar.MONTH, direction);
		resetTime(false);
		currentMonthsFirstDate = calendar.getTime();
		calendarComponent.setStartDate(currentMonthsFirstDate);

		updateCaptionLabel();

		calendar.add(GregorianCalendar.MONTH, 1);
		calendar.add(GregorianCalendar.DATE, -1);
		resetCalendarTime(true);
	}

	private void rollWeek(int direction) {
		calendar.add(GregorianCalendar.WEEK_OF_YEAR, direction);
		calendar.set(GregorianCalendar.DAY_OF_WEEK,
				calendar.getFirstDayOfWeek());
		resetCalendarTime(false);
		resetTime(true);
		calendar.add(GregorianCalendar.DATE, 6);
		calendarComponent.setEndDate(calendar.getTime());
	}

	private void rollDate(int direction) {
		calendar.add(GregorianCalendar.DATE, direction);
		resetCalendarTime(false);
		resetCalendarTime(true);
	}

	private void updateCaptionLabel() {
		DateFormatSymbols s = new DateFormatSymbols(TutosApplication.getInstance().getMainWindow().getLocale());
		String month = s.getShortMonths()[calendar.get(GregorianCalendar.MONTH)];
		captionLabel.setValue(month + " "
				+ calendar.get(GregorianCalendar.YEAR));
	}

	/*
	 * Switch the view to week view.
	 */
	public void switchToWeekView() {
		viewMode = Mode.WEEK;
		weekButton.setVisible(false);
		monthButton.setVisible(true);
	}

	/*
	 * Switch the Calendar component's start and end date range to the target
	 * month only. (sample range: 01.01.2010 00:00.000 - 31.01.2010 23:59.999)
	 */
	public void switchToMonthView() {
		viewMode = Mode.MONTH;
		monthButton.setVisible(false);
		weekButton.setVisible(false);

		calendar.setTime(currentMonthsFirstDate);
		calendarComponent.setStartDate(currentMonthsFirstDate);

		updateCaptionLabel();

		calendar.add(GregorianCalendar.MONTH, 1);
		calendar.add(GregorianCalendar.DATE, -1);
		resetCalendarTime(true);
	}

	/*
	 * Switch to day view (week view with a single day visible).
	 */
	public void switchToDayView() {
		viewMode = Mode.DAY;
		monthButton.setVisible(true);
		weekButton.setVisible(true);
	}

	private void resetCalendarTime(boolean resetEndTime) {
		resetTime(resetEndTime);
		if (resetEndTime) {
			calendarComponent.setEndDate(calendar.getTime());
		} else {
			calendarComponent.setStartDate(calendar.getTime());
			updateCaptionLabel();
		}
	}

	/*
	 * Resets the calendar time (hour, minute second and millisecond) either to
	 * zero or maximum value.
	 */
	private void resetTime(boolean max) {
		if (max) {
			calendar.set(GregorianCalendar.HOUR_OF_DAY,
					calendar.getMaximum(GregorianCalendar.HOUR_OF_DAY));
			calendar.set(GregorianCalendar.MINUTE,
					calendar.getMaximum(GregorianCalendar.MINUTE));
			calendar.set(GregorianCalendar.SECOND,
					calendar.getMaximum(GregorianCalendar.SECOND));
			calendar.set(GregorianCalendar.MILLISECOND,
					calendar.getMaximum(GregorianCalendar.MILLISECOND));
		} else {
			calendar.set(GregorianCalendar.HOUR_OF_DAY, 0);
			calendar.set(GregorianCalendar.MINUTE, 0);
			calendar.set(GregorianCalendar.SECOND, 0);
			calendar.set(GregorianCalendar.MILLISECOND, 0);
		}
	}
	
	private class MyBasicEventProvider extends BasicEventProvider{
		
		private static final long serialVersionUID = 4956074732076563166L;
		private List<Evento> eventos;
		
		public MyBasicEventProvider(List<Evento> eventos){
			this.eventos = eventos;
			for(Evento ev : eventos){
				Eventos evs = new Eventos(ev);
				evs.addListener(this);
				eventList.add(evs);
			}
			fireEventSetChange();
		}
		
		public void addEvent(CalendarEvent event) {
	        eventList.add(event);
	        eventos.add(((Eventos)event).getEvento());
	        if (event instanceof Eventos) {
	            ((Eventos) event).addListener(this);
	        }
	        fireEventSetChange();
	    }
		
		public void removeEvent(CalendarEvent event) {
	        eventList.remove(event);
	        eventos.remove(((Eventos)event).getEvento());
	        if (event instanceof Eventos) {
	            ((Eventos) event).removeListener(this);
	        }
	        fireEventSetChange();
	    }
		
		public boolean containsEvent(Eventos event) {
	        return eventList.contains(event);
	    }
		
	}
	
	public Component getComponent() {
		return layout;
	}
}